package com.wing.member.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Editor;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wing.common.enums.CalculationTypeEnum;
import com.wing.member.dao.MemberRelationDao;
import com.wing.member.model.entity.MemberRelation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 用户关系-ServiceImpl
 *
 * @author
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class MemberRelationServiceImpl extends ServiceImpl<MemberRelationDao, MemberRelation> implements MemberRelationService {

    @Override
    public int addNode(Long memberId, Long parentId) {
        int flag;

        if(parentId != null){
            //插入-父级关联节点关联自己，楼层+1
            List<MemberRelation> memberRelationList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("descendant", parentId));
            if(memberRelationList != null && memberRelationList.size() > 0){
                for(MemberRelation memberRelation : memberRelationList){
                    MemberRelation mr = new MemberRelation(memberRelation.getAncestor(), memberId, memberRelation.getDistance() + 1);
                    flag = this.baseMapper.insert(mr);
                    if(flag <= 0){
                        return flag;
                    }
                }
            }
        }

        //插入-自己关联自己
        MemberRelation self = new MemberRelation(memberId, memberId, 0);
        flag = this.baseMapper.insert(self);

        return flag;
    }

    @Override
    public int insertNode(Long memberId, Long parentId, Long childId) {
        int flag;

        //找出子节点下所有节点(包括自己)
        List<MemberRelation> descendantList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("ancestor", childId));
        if(descendantList != null && descendantList.size() > 0){
            for(MemberRelation memberRelation : descendantList){
                //每个子节点关联的祖先节点楼层 + 1
                List<MemberRelation> ancestorList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("descendant", childId).ne("distance", 0));
                if(ancestorList != null && ancestorList.size() > 0){
                    for(MemberRelation act : ancestorList){
                        act.setDistance(act.getDistance() + 1);
                        flag = this.baseMapper.updateById(act);
                        if(flag <= 0){
                            return flag;
                        }
                    }
                }

                //每个子节点关联新插入节点
                MemberRelation mrn = new MemberRelation(memberId, memberRelation.getDescendant(), memberRelation.getDistance() + 1);
                flag = this.baseMapper.insert(mrn);
                if(flag <= 0){
                    return flag;
                }
            }
        }

        //插入到父节点下
        flag = addNode(memberId, parentId);

        return flag;
    }

    @Override
    public int deleteNode(Long memberId) {
        int flag = 0;

        //删除关联子节点关联
        List<MemberRelation> descendantList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("ancestor", memberId));
        if(descendantList != null && descendantList.size() > 0){
            for(MemberRelation memberRelation : descendantList){
                flag = this.baseMapper.deleteById(memberRelation.getId());
                if(flag <= 0){
                    return flag;
                }
            }
        }

        //删除父节点关联
        List<MemberRelation> ancestorList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("descendant", memberId));
        if(ancestorList != null && ancestorList.size() > 0){
            for(MemberRelation memberRelation : ancestorList){
                flag = this.baseMapper.deleteById(memberRelation.getId());
                if(flag <= 0){
                    return flag;
                }
            }
        }

        return flag;
    }

    @Override
    public int moveNode(Long memberId, Long newParentId){
        int flag;
        //删除节点
        flag = deleteNode(memberId);

        //添加到新父节点下
        if(flag > 0){
            flag = addNode(memberId, newParentId);
        }
        return flag;
    }

    @Override
    public int moveNodeTree(Long nodeId, Long newParentId){
        int flag;

        //找出节点下所有子节点
        List<MemberRelation> childList = this.baseMapper.selectList(new QueryWrapper<MemberRelation>().eq("ancestor", nodeId).ne("distance", 1));

        //移动节点到父节点下
        flag = moveNode(nodeId, newParentId);

        //如果有子节点，遍历子节点，递归重复上面操作
        if(childList != null && childList.size() > 0){
            for(MemberRelation child : childList){
                moveNodeTree(child.getDescendant(), nodeId);
                if(flag <= 0){
                    return flag;
                }
            }
        }

        return flag;
    }

    @Override
    public JSONObject nodeTree(Long nodeId) {
        return null;
    }

    @Override
    public List<Long> descendant(Long nodeId, Boolean hasSelf) {
        QueryWrapper queryWrapper = new QueryWrapper<MemberRelation>();
        queryWrapper.eq("ancestor", nodeId);
        if(!hasSelf){
            queryWrapper.ne("distance", 0);
        }
        List<MemberRelation> descendantList = this.baseMapper.selectList(queryWrapper);
        List<Long> longList = new ArrayList<>();
        if(descendantList != null && descendantList.size() > 0){
            for(MemberRelation memberRelation : descendantList){
                longList.add(memberRelation.getDescendant());
            }
            return longList;
        }
        return null;
    }

    @Override
    public List<Long> descendantByDistance(Long nodeId, Integer distance, CalculationTypeEnum type, Boolean hasSelf) {
        QueryWrapper queryWrapper = new QueryWrapper<MemberRelation>();
        queryWrapper.eq("ancestor", nodeId);
        if(!hasSelf){
            queryWrapper.ne("distance", 0);
        }
        if(distance != null && type != null){
            switch (type){
                case EQ:
                    queryWrapper.eq("distance", distance);
                    break;
                case GE:
                    queryWrapper.ge("distance", distance);
                    break;
                case GT:
                    queryWrapper.gt("distance", distance);
                    break;
                case LE:
                    queryWrapper.le("distance", distance);
                    break;
                case LT:
                    queryWrapper.lt("distance", distance);
                    break;
                default:
                    break;
            }
        }
        List<MemberRelation> descendantList = this.baseMapper.selectList(queryWrapper);
        List<Long> longList = new ArrayList<>();
        if(descendantList != null && descendantList.size() > 0){
            for(MemberRelation memberRelation : descendantList){
                longList.add(memberRelation.getDescendant());
            }
            return longList;
        }
        return null;
    }

    @Override
    public List<Long> descendantByDistance(Long nodeId, int distance, CalculationTypeEnum type, int distance2, CalculationTypeEnum type2,  Boolean hasSelf) {
        QueryWrapper queryWrapper = new QueryWrapper<MemberRelation>();
        queryWrapper.eq("ancestor", nodeId);
        if(!hasSelf){
            queryWrapper.ne("distance", 0);
        }
        if(type != null){
            switch (type){
                case EQ:
                    queryWrapper.eq("distance", distance);
                    break;
                case GE:
                    queryWrapper.ge("distance", distance);
                    break;
                case GT:
                    queryWrapper.gt("distance", distance);
                    break;
                case LE:
                    queryWrapper.le("distance", distance);
                    break;
                case LT:
                    queryWrapper.lt("distance", distance);
                    break;
                default:
                    break;
            }
        }
        if(type2 != null){
            switch (type){
                case EQ:
                    queryWrapper.eq("distance", distance2);
                    break;
                case GE:
                    queryWrapper.ge("distance", distance2);
                    break;
                case GT:
                    queryWrapper.gt("distance", distance2);
                    break;
                case LE:
                    queryWrapper.le("distance", distance2);
                    break;
                case LT:
                    queryWrapper.lt("distance", distance2);
                    break;
                default:
                    break;
            }
        }
        List<MemberRelation> descendantList = this.baseMapper.selectList(queryWrapper);
        List<Long> longList = new ArrayList<>();
        if(descendantList != null && descendantList.size() > 0){
            for(MemberRelation memberRelation : descendantList){
                longList.add(memberRelation.getDescendant());
            }
            return longList;
        }
        return null;
    }

    @Override
    public List<Long> ancestor(Long nodeId, Boolean hasSelf) {
        QueryWrapper queryWrapper = new QueryWrapper<MemberRelation>();
        queryWrapper.eq("descendant", nodeId);
        if(!hasSelf){
            queryWrapper.ne("distance", 0);
        }
        List<MemberRelation> ancestorList = this.baseMapper.selectList(queryWrapper);
        List<Long> longList = new ArrayList<>();
        if(ancestorList != null && ancestorList.size() > 0){
            for(MemberRelation memberRelation : ancestorList){
                longList.add(memberRelation.getAncestor());
            }
            return longList;
        }
        return null;
    }

    @Override
    public List<Long> descendantAndIgnore(Long nodeId, Boolean hasSelf, List<Long> ignoreNodeIdList, Boolean hasIgnoreNodeSelf) {
        List<Long> descendant = descendant(nodeId, hasSelf);
        if(CollUtil.isEmpty(descendant)){
            return null;
        }
        if(CollUtil.isNotEmpty(ignoreNodeIdList)){
            for(Long ignoreNodeId : ignoreNodeIdList){
                List<Long> longList = descendant(ignoreNodeId, hasIgnoreNodeSelf);
                if(CollUtil.isNotEmpty(longList)){
                     descendant = CollUtil.filter(descendant, (Editor<Long>) aLong -> {
                         if(!longList.contains(aLong)){
                            return aLong;
                         }
                         return null;
                     });
                }
            }
        }
        return descendant;
    }


}
